﻿using System;

namespace Eniux.SharpOpenGL
{
    /// <summary>
    /// HiddenWindowRender渲染上下文
    /// </summary>
    public class HiddenWindowRenderContext : RenderContext
    {
        #region 变量

        /// <summary>
        /// window句柄
        /// </summary>
        protected IntPtr windowHandle = IntPtr.Zero;
        private static Win32.WndProc wndProcDelegate = new Win32.WndProc(WndProc);
        
        #endregion

        #region 构造

        /// <summary>
        /// 默认构造
        /// </summary>
        public HiddenWindowRenderContext()
        {
            //设置GDI可用
            GDIDrawingEnabled = true;
        } 

        #endregion

        #region 重写方法

        /// <summary>
        /// 创建渲染上下文
        /// </summary>
        /// <param name="gl">OpenGL上下文</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <param name="bitDepth">位深</param>
        /// <param name="parameter">参数</param>
        /// <returns>bool</returns>
        public override bool Create(OpenGL gl, int width, int height, int bitDepth, object parameter)
        {
            //  Call the base.
            base.Create(gl, width, height, bitDepth, parameter);

            //	Create a new window class, as basic as possible.                
            Win32.WNDCLASSEX wndClass = new Win32.WNDCLASSEX();
            wndClass.Init();
            wndClass.style = Win32.ClassStyles.HorizontalRedraw | Win32.ClassStyles.VerticalRedraw | Win32.ClassStyles.OwnDC;
            wndClass.lpfnWndProc = wndProcDelegate;
            wndClass.cbClsExtra = 0;
            wndClass.cbWndExtra = 0;
            wndClass.hInstance = IntPtr.Zero;
            wndClass.hIcon = IntPtr.Zero;
            wndClass.hCursor = IntPtr.Zero;
            wndClass.hbrBackground = IntPtr.Zero;
            wndClass.lpszMenuName = null;
            wndClass.lpszClassName = "SharpGLRenderWindow";
            wndClass.hIconSm = IntPtr.Zero;
            Win32.RegisterClassEx(ref wndClass);

            //	Create the window. Position and size it.
            windowHandle = Win32.CreateWindowEx(0,
                          "SharpGLRenderWindow",
                          "",
                          Win32.WindowStyles.WS_CLIPCHILDREN | Win32.WindowStyles.WS_CLIPSIBLINGS | Win32.WindowStyles.WS_POPUP,
                          0, 0, width, height,
                          IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            //	Get the window device context.
            deviceContextHandle = Win32.GetDC(windowHandle);

            //	Setup a pixel format.
            Win32.PIXELFORMATDESCRIPTOR pfd = new Win32.PIXELFORMATDESCRIPTOR();
            pfd.Init();
            pfd.nVersion = 1;
            pfd.dwFlags = Win32.PFD_DRAW_TO_WINDOW | Win32.PFD_SUPPORT_OPENGL | Win32.PFD_DOUBLEBUFFER;
            pfd.iPixelType = Win32.PFD_TYPE_RGBA;
            pfd.cColorBits = (byte)bitDepth;
            pfd.cDepthBits = 16;
            pfd.cStencilBits = 8;
            pfd.iLayerType = Win32.PFD_MAIN_PLANE;

            //	Match an appropriate pixel format 
            int iPixelformat;
            if ((iPixelformat = Win32.ChoosePixelFormat(deviceContextHandle, pfd)) == 0)
                return false;

            //	Sets the pixel format
            if (Win32.SetPixelFormat(deviceContextHandle, iPixelformat, pfd) == 0)
            {
                return false;
            }

            //	Create the render context.
            renderContextHandle = Win32.wglCreateContext(deviceContextHandle);

            //  Make the context current.
            MakeCurrent();

            //  Return success.
            return true;
        }

        /// <summary>
        /// 销毁渲染上下文
        /// </summary>
        public override void Destroy()
        {
            //	释放设备
            Win32.ReleaseDC(windowHandle, deviceContextHandle);

            //销毁window
            Win32.DestroyWindow(windowHandle);

            //	Call the base, which will delete the render context handle.
            base.Destroy();
        }

        /// <summary>
        ///设置渲染上下文尺寸.
        /// </summary>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        public override void SetDimensions(int width, int height)
        {
            //  Call the base.
            base.SetDimensions(width, height);

            //	Set the window size.
            Win32.SetWindowPos(windowHandle, IntPtr.Zero, 0, 0, Width, Height,
                Win32.SetWindowPosFlags.SWP_NOACTIVATE |
                Win32.SetWindowPosFlags.SWP_NOCOPYBITS |
                Win32.SetWindowPosFlags.SWP_NOMOVE |
                Win32.SetWindowPosFlags.SWP_NOOWNERZORDER);
        }

        /// <summary>
        /// 将呈现位块的数据给上下文.
        /// </summary>
        /// <param name="hdc">The HDC.</param>
        public override void Blit(IntPtr hdc)
        {
            if (deviceContextHandle != IntPtr.Zero || windowHandle != IntPtr.Zero)
            {
                //	Swap the buffers.
                Win32.SwapBuffers(deviceContextHandle);

                //  Get the HDC for the graphics object.
                Win32.BitBlt(hdc, 0, 0, Width, Height, deviceContextHandle, 0, 0, Win32.SRCCOPY);
            }
        }

        /// <summary>
        ///  确定渲染当前上下文
        /// </summary>
        public override void MakeCurrent()
        {
            if (renderContextHandle != IntPtr.Zero)
                Win32.wglMakeCurrent(deviceContextHandle, renderContextHandle);
        } 
        #endregion

        #region 方法

       private static  IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
        {
            return Win32.DefWindowProc(hWnd, msg, wParam, lParam);
        } 
        #endregion
    }
}
